package com.gutsyzhan.bilibili.service.impl;

import com.gutsyzhan.bilibili.dao.VideoDao;
import com.gutsyzhan.bilibili.domain.*;
import com.gutsyzhan.bilibili.exception.ConditionException;
import com.gutsyzhan.bilibili.service.UserCoinService;
import com.gutsyzhan.bilibili.service.UserService;
import com.gutsyzhan.bilibili.service.VideoService;
import com.gutsyzhan.bilibili.util.FastDFSUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class VideoServiceImpl implements VideoService {
    @Resource
    private VideoDao videoDao;

    @Resource
    private FastDFSUtil fastDFSUtil;

    @Resource
    private UserCoinService userCoinService;

    @Resource
    private UserService userService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void addVideo(Video video) {
        Date now = new Date();
        video.setCreateTime(now);
        videoDao.addVideo(video);
        Long videoId = video.getId();
        List<VideoTag> videoTagList = video.getVideoTagList();
        videoTagList.forEach(videoTag -> {
            videoTag.setCreateTime(now);
            videoTag.setVideoId(videoId);
        });
        videoDao.batchAddVideoTags(videoTagList);
    }

    @Override
    public PageResult<Video> pageListVideos(Integer no, Integer size, String area) {
        if(no == null || size == null){
            throw new ConditionException("参数异常！");
        }
        Map<String, Object> params = new HashMap<>();
        params.put("start", (no -1) * size);
        params.put("limit", size);
        params.put("area", area);
        List<Video> list = new ArrayList<>();
        Integer total = videoDao.pageCountVideos(params);
        if(total > 0){
            list = videoDao.pageListVideos(params);

        }
        return new PageResult<>(total, list);
    }

    @Override
    public void viewVideoOnlineBySlices(HttpServletRequest request, HttpServletResponse response, String path) throws Exception {
        fastDFSUtil.viewVideoOnlineBySlices(request, response, path);
    }

    @Override
    public void addVideoLike(Long userId, Long videoId) {
        Video video = videoDao.getVideoById(videoId);
        if(video == null){
            throw new ConditionException("非法视频!");
        }
        VideoLike videoLike = videoDao.getVideoLikeByUserIdAndVideoId(userId, videoId);
        if(videoLike != null){
            throw new ConditionException("已经点赞过!");
        }
        videoLike = new VideoLike();
        videoLike.setVideoId(videoId);
        videoLike.setUserId(userId);
        videoLike.setCreateTime(new Date());
        videoDao.addVideoLike(videoLike);
    }

    @Override
    public void deleteVideoLike(Long userId, Long videoId) {
        videoDao.deleteVideoLike(userId, videoId);
    }

    @Override
    public Map<String, Object> getVideoLikes(Long userId, Long videoId) {
        Long count = videoDao.getVideoLikes(videoId);
        VideoLike videoLike = videoDao.getVideoLikeByUserIdAndVideoId(userId, videoId);
        boolean like = videoLike != null;
        Map<String, Object> result = new HashMap<>();
        result.put("count", count);
        result.put("like", like);
        return result;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void addVideoCollection(Long userId, VideoCollection videoCollection) {
        Long videoId = videoCollection.getVideoId();
        Long groupId = videoCollection.getGroupId();
        if(videoId == null || groupId == null){
            throw new ConditionException("参数异常!");
        }
        Video video = videoDao.getVideoById(videoId);
        if(video == null){
            throw new ConditionException("非法视频!");
        }
        //删除原有的视频收藏
        videoDao.deleteVideoCollection(userId ,videoId);
        //添加新的视频收藏
        videoCollection.setCreateTime(new Date());
        videoCollection.setUserId(userId);
        videoDao.addVideoCollection(videoCollection);
    }

    @Override
    public void deleteVideoCollection(Long userId, Long videoId) {
        videoDao.deleteVideoCollection(userId, videoId);
    }

    @Override
    public Map<String, Object> getVideoCollections(Long userId, Long videoId) {
        Long count = videoDao.getVideoCollections(videoId);
        VideoCollection videoCollection = videoDao.getVideoCollectionByUserIdAndVideoId(userId, videoId);
        boolean collection = videoCollection != null;
        Map<String, Object> result = new HashMap<>();
        result.put("count", count);
        result.put("collection", collection);
        return result;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void addVideoCoin(Long userId, VideoCoin videoCoin) {
        Long videoId = videoCoin.getVideoId();
        Long amount = videoCoin.getAmount();
        if(null == videoId){
            throw new ConditionException("参数异常!");
        }
        Video video = videoDao.getVideoById(videoId);
        if(video == null){
            throw new ConditionException("非法视频!");
        }
        //查询当前登录用户是否有足够的硬币
        Long userCoinsAmount = userCoinService.getUserCoinsAmount(userId);
        userCoinsAmount = userCoinsAmount == null ? 0:userCoinsAmount;
        if(amount > userCoinsAmount){
            throw new ConditionException("硬币数量不足!");
        }
        //查询当前登录用户对该视频已经投了多少硬币
        VideoCoin dbVideoCoin = videoDao.getVideoCoinByUserIdAndVideoId(userId, videoId);
        //新增视频投币
        Date now = new Date();
        videoCoin.setUserId(userId);
        if (null == dbVideoCoin){
            videoCoin.setCreateTime(now);
            videoDao.addVideoCoin(videoCoin);
        }else{
            Long dbAmount = dbVideoCoin.getAmount();
            //TODO 原子操作
            dbAmount += amount;
            //更新视频投币
            videoCoin.setAmount(dbAmount);
            videoCoin.setUpdateTime(now);
            videoDao.updateVideoCoin(videoCoin);
        }
        //更新当前用户的硬币总数
        userCoinService.updateUserCoinsAmount(userId, (userCoinsAmount - amount));
    }

    @Override
    public Map<String, Object> getVideoCoins(Long userId, Long videoId) {
        Long count = videoDao.getVideoCoinsAmount(videoId);
        VideoCoin videoCoin = videoDao.getVideoCoinByUserIdAndVideoId(userId, videoId);
        boolean coin = videoCoin != null;
        Map<String, Object> result = new HashMap<>();
        result.put("count", count);
        result.put("coin", coin);
        return result;
    }

    @Override
    public void addVideoComment(Long userId, VideoComment videoComment) {
        Long videoId = videoComment.getVideoId();
        if(null == videoId){
            throw new ConditionException("参数异常!");
        }
        Video video = videoDao.getVideoById(videoId);
        if(video == null){
            throw new ConditionException("非法视频!");
        }
        videoComment.setUserId(userId);
        videoComment.setCreateTime(new Date());
        videoDao.addVideoComment(videoComment);
    }

    @Override
    public PageResult<VideoComment> pageListVideoComments(Long videoId, Integer no, Integer size) {
        Video video = videoDao.getVideoById(videoId);
        if(video == null){
            throw new ConditionException("非法视频!");
        }
        Map<String, Object> params = new HashMap<>();
        params.put("start", (no-1)* size);
        params.put("limit", size);
        params.put("videoId", videoId);
        //获取一级评论的数量，也就是rootId为null的情况
        Integer total = videoDao.pageCountVideoComments(params);
        List<VideoComment> list = new ArrayList<>();
        if(total > 0){
            //获取一级评论的列表
            list = videoDao.pageListVideoComments(params);
            //批量获取二级评论
            //先获取所有一级评论的评论id集合
            List<Long> parentIdList = list.stream().map(VideoComment::getId).collect(Collectors.toList());
            //再使用一级评论的评论id集合去批量查询二级评论
            List<VideoComment> childCommentList = videoDao.batchGetVideoCommentsByRootIds(parentIdList);
            //批量查询用户信息
            //先获取所有一级评论的用户id集合
            Set<Long> userIdSet = list.stream().map(VideoComment::getUserId).collect(Collectors.toSet());
            //再获取所有二级评论的用户id集合
            Set<Long> replyUserIdSet = childCommentList.stream().map(VideoComment::getReplyUserId).collect(Collectors.toSet());
            userIdSet.addAll(replyUserIdSet);
            //批量查询用户信息
            List<UserInfo> userInfoList = userService.batchGetUserInfoByUserIds(userIdSet);
            //对用户信息以userId为key,用户信息为value进行分组
            Map<Long, UserInfo> userInfoMap = userInfoList.stream().collect(Collectors.toMap(UserInfo::getId, userInfo -> userInfo));
            //遍历一级评论列表，目的是填充里面每个评论的二级评论信息及一级评论用户信息
            list.forEach(comment -> {
                Long id = comment.getId();
                List<VideoComment> childList = new ArrayList<>();
                childCommentList.forEach(child -> {
                    if(Objects.equals(id, child.getRootId())){
                        //说明当前二级评论归属于当前的一级评论，那么设置二级评论的相关信息
                        child.setUserInfo(userInfoMap.get(child.getUserId()));
                        child.setReplyUserInfo(userInfoMap.get(child.getReplyUserId()));
                        childList.add(child);
                    }
                });
                comment.setChildList(childList);
                comment.setUserInfo(userInfoMap.get(comment.getUserId()));
            });
        }
        return new PageResult<>(total, list);
    }

    @Override
    public Map<String, Object> getVideoDetails(Long videoId) {
        Map<String, Object> result = new HashMap<>();
        Video video = videoDao.getVideoDetails(videoId);
        Long userId = video.getUserId();
        User user = userService.getUserInfo(userId);
        UserInfo userInfo = user.getUserInfo();
        result.put("video", video);
        result.put("userInfo", userInfo);
        return result;
    }
}
